package gui.panels.media;

import gui.panels.media.dnd.MediaDragGestureRecognizer;
import gui.panels.media.dnd.MediaDragSourceListener;

import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.FileDialog;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;

import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.GainControl;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Player;
import javax.media.PrefetchCompleteEvent;
import javax.media.RealizeCompleteEvent;
import javax.media.Time;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.logging.Level;

import logger.ApplicationLogger;
import media.process.MediaSliceContainer;

public class VideoControlsPanel extends JPanel  implements MouseMotionListener,
MouseListener, ControllerListener ,Runnable, MediaContainer  {

	private static final long serialVersionUID = 1L;
	private Player player = null;
	private Image image = null;
	private Icon icon;  
	private GainControl gain = null;
	private int timex = -1;
	private Point startPoint;
	private Point startLocation; 
	private boolean closing;
	protected boolean notOutside = true;
	protected String lastDir = null;
	private MediaSliceContainer msc = null;
	private String mediaUrl;
	private DragSource dragSource =null;
	
	
	/**
	 * Locations of the icons on the control bar.
	 */	
	int COMPONENTS[][] = {
			{ 47, 3, 52, 14 },
			{ 54, 3, 59, 14 },
			{ 62, 3, 69, 18 },
			{ 70, 3, 79, 15 },
			{ 114, 7, 136, 17 },
			{ 141, 7, 211, 17 },
			{ 287, 7, 300, 17 },
			{302, 7, 314, 17 }
	};
	protected boolean inVolume = false;
	protected boolean inTime = false;
	static final int PLAY = 0;
	static final int PAUSE = 1;
	static final int REWIND = 2;
	static final int EJECT = 3;
	static final int VOLUME = 4;
	static final int MEDIATIME = 5;
	static final int MAXIMIZE = 6;
	static final int CLOSE = 7;

	static final int GAINWIDTH = 22;


	private JPanel container;
	/**
	 * This is the default constructor
	 */
	public VideoControlsPanel(JPanel container) {
		super();
		this.container = container;
		initialize();


	}

	/**
	 * This method initializes this
	 * 
	 */
	private void initialize() {
		dragSource = DragSource.getDefaultDragSource() ;
		
		this.setSize(new Dimension(233, 18));
		this.setIcon(new ImageIcon(getClass().getResource("/img/jamp.jpg")));
		addMouseListener(this);
		addMouseMotionListener(this);
		this.revalidate();

	}



	@Override
	public void controllerUpdate(ControllerEvent ce) {


		if (ce instanceof RealizeCompleteEvent) {
			this.removeAll();
			// Get the player's visual component, if any, and put it in a Window above
			// the control panel.
			Component vis = player.getVisualComponent();
			
			
			if (vis != null) {

				vis.setSize(container.getSize());
				container.add(vis);
				msc = new MediaSliceContainer(new java.io.File(mediaUrl), null, null);
				MediaDragSourceListener mdgs = new MediaDragSourceListener();

				MediaDragGestureRecognizer mdgr = new MediaDragGestureRecognizer(msc, mdgs);
				//Component video = this.getPlayer().getVisualComponent();
				
				
				//Component vis = player.getVisualComponent();
				dragSource.createDefaultDragGestureRecognizer( 
						vis,
						//Aqui indicamos los tipos de acciones posibles que queremos: descritas en la clase DndConstants
						DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE |
						DnDConstants.ACTION_LINK,
						mdgr );
				

			}
			// Start the player
			player.start();
		} else if (ce instanceof EndOfMediaEvent) {
			rewind();
			play();
		} else if (ce instanceof PrefetchCompleteEvent) {
			// Get the GainControl from the player, if any, to control sound volume
			gain = (GainControl) player.getControl("javax.media.GainControl");
			repaint();
		}

	}

	// Start the player
	private void play() {
		if (player != null){
			
			
			
			
			player.start();
		}
	}

	// Stop the player
	private void pause() {
		if (player != null)
			player.stop();
	}


	// Seek back to zero
	private void rewind() {
		if (player != null) {
			player.setMediaTime(new Time(0));
			if (player.getTargetState() < Player.Started)
				player.prefetch();
		}
	}


	protected void paintComponent(Graphics g) {  

		Graphics2D g2 =(Graphics2D) g;

		if (gain != null) {
			int cx = (int) (gain.getLevel() * GAINWIDTH +
					COMPONENTS[VOLUME][0] + 0.5);
			int sy = COMPONENTS[VOLUME][1];
			int ey = COMPONENTS[VOLUME][3];
			g2.setColor(Color.cyan.darker());
			g2.drawLine(cx, sy + 1, cx, ey - 1);
			g2.drawLine(cx - 1, sy + 2, cx - 1, ey - 2);
			g2.drawLine(cx + 1, sy + 2, cx + 1, ey - 2);
		}
		if (player != null && timex >= 0) {
			int cx = timex + COMPONENTS[MEDIATIME][0];
			int sy = COMPONENTS[MEDIATIME][1];
			int ey = COMPONENTS[MEDIATIME][3];
			g2.setColor(Color.cyan.darker());
			g2.drawLine(cx, sy + 1, cx, ey - 1);
			g2.drawLine(cx - 1, sy + 2, cx - 1, ey - 2);
			g2.drawLine(cx + 1, sy + 2, cx + 1, ey - 2);
		}
		if (player == null) {
			g2.setColor(Color.red);
			g2.drawLine(24, 12, 95, 12);
			g2.drawLine(113, 12, 300, 12);
		}
		if(getImage()!=null)  

			g2.drawImage(getImage(), 0, 0, getWidth(), getHeight(), null);  

	}  

	public void mousePressed(MouseEvent parm1) {

		ApplicationLogger.getLogger().log(Level.INFO, "Mouse presionado sobre los controles de video");
		startPoint = parm1.getPoint();
		notOutside = false;
		inVolume = false;
		inTime = false;
		ApplicationLogger.getLogger().log(Level.INFO, "Posicion del mouse: x= "+startPoint.x+" y= "+startPoint.y);
		for (int i = 0; i < COMPONENTS.length; i++) {
			if (startPoint.x >= COMPONENTS[i][0] &&
					startPoint.y >= COMPONENTS[i][1] &&
					startPoint.x <= COMPONENTS[i][2] &&
					startPoint.y <= COMPONENTS[i][3] ) {

				switch (i) {
				case PLAY:
					play();
					break;
				case PAUSE:
					pause();
					break;
				case REWIND:
					rewind();
					break;
				case EJECT:
					eject();
					break;
				case VOLUME:
					inVolume = true;
					volumeDragged(startPoint.x);
					break;
				case MEDIATIME:
					inTime = true;
					timeDragged(startPoint.x);
					break;
				case CLOSE:
					closing = true;
					close();
					if (player == null)
						System.exit(0);
					break;

				}
				notOutside = true;
				break;
			}
		}
	}

	// Stop and close the player
	private void close() {
		if (player != null) {
			player.stop();
			player.close();
		}
	}
	private void timeDragged(int x) {
		if (player == null)
			return;
		// Determine the requested media time based on duration of the file
		// and position of the mouse in the control panel.
		long dura = player.getDuration().getNanoseconds();
		if (dura < 0 || dura > 3 * 3600 * 1000000000L)
			return;
		long nano = (long) ((float) (x - COMPONENTS[MEDIATIME][0]) /
				(COMPONENTS[MEDIATIME][2] -
						COMPONENTS[MEDIATIME][0] + 1) * dura);
		if (nano < 0) nano = 0;
		if (nano > dura) nano = dura;
		// Set the media time
		player.setMediaTime(new Time(nano));
		if (player.getTargetState() < Player.Started)
			player.prefetch();
		repaint();
	}


	private void volumeDragged(int x) {
		if (gain == null)
			return;
		// Determine volume level from mouse position in the control panel
		float level = (x - COMPONENTS[VOLUME][0]) / (float) GAINWIDTH;
		if (level < 0f) level = 0f;
		if (level > 1f) level = 1f;
		// Set the volume level through the GainControl from the player
		gain.setLevel(level);
		// Update the GUI
		repaint();
	}

	// Close the player and open a new file
	private void eject() {
		Thread cl = new EjectThread();
		cl.start();
	}

	/**
	 * Create a player for the URL and realize it.
	 */
	private void loadMovie(String movieURL) {
		// Prepend a "file:" if no protocol is specified
		mediaUrl=movieURL;
		
		if (movieURL.indexOf(":") < 3)
			movieURL = "file:" + movieURL;
		// Try to create a player
		try {
			player = Manager.createPlayer(new MediaLocator(movieURL));
			player.addControllerListener(this);
			player.realize();
		} catch (Exception e) {
			ApplicationLogger.getLogger().log(Level.SEVERE, "Error al inicializar el reproductor de video");
			return;
		}
	}

	public Image getImage() {  

		return image;  

	}  

	public void setImage(Image image) {  

		this.image = image;  

	}  

	public Icon getIcon() {  

		return icon;  

	}  

	public void setIcon(Icon icon){  

		this.icon=icon;  

		setImage(((ImageIcon)icon).getImage());  

	}


	public void doEject() {
		ApplicationLogger.getLogger().log(Level.INFO, "Ejecting Video");
		FileDialog fd;
		close();
		// Block till we receive ControllerClosedEvent
		while (player != null) {
			try {
				Thread.currentThread().sleep(100);
			} catch (InterruptedException ie) {
			}
		}
		fd = new FileDialog(new JFrame(), "Open File", FileDialog.LOAD);
		if (lastDir != null)
			fd.setDirectory(lastDir);
		fd.show();
		lastDir = fd.getDirectory();
		String filename = fd.getFile();
		if (filename == null)
			return;
		else {
			loadMovie(lastDir + filename);
		}
		fd.dispose();
	}


	@Override
	public void run() {
		while (true) {
			if (player != null) {
				
				
				long nano = player.getMediaTime().getNanoseconds();
				long dura = player.getDuration().getNanoseconds();
				if (dura >= 0 && dura < (long) 3 * 3600 * 1000000000L) {

					timex = (int) (((float) nano / dura) *
							(COMPONENTS[MEDIATIME][2] -
									COMPONENTS[MEDIATIME][0] + 1));
					repaint();
				}
			}
			try {
				Thread.currentThread().sleep(250);
			} catch (InterruptedException ie) {
			}
		}

	}  

	class EjectThread extends Thread {

		public EjectThread() {
		}

		public void run() {
			doEject();
		}
	}

	@Override
	public void mouseDragged(MouseEvent parm1) {
		if (notOutside) {
			if (inVolume)
				volumeDragged(parm1.getPoint().x);
			else if (inTime)
				timeDragged(parm1.getPoint().x);
			return;
		}
		// Drag the panel around
		startLocation = getLocation();
		setLocation(startLocation.x - startPoint.x + parm1.getPoint().x,
				startLocation.y - startPoint.y + parm1.getPoint().y);

		Toolkit.getDefaultToolkit().sync();
		repaint();

	}




	@Override
	public void mouseMoved(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}




	@Override
	public void mouseClicked(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}




	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}




	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}




	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	public Player getPlayer() {

		return this.player;
	}

	public String getMediaUrl() {
		
		return mediaUrl;
	}

	@Override
	public void setStartTime(long time) {
		msc.setStartTime(time);
		
	}

	@Override
	public void setStopTime(long time) {
		msc.setStopTime(time);
		
	}
	
	
	
}  